﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using UtilZ.Dotnet.WindowsDesktopEx.WPF;

namespace UtilZ.Dotnet.WindowsDesktopEx.WPF
{
    /// <summary>
    /// 数值输入控件
    /// </summary>
    public partial class NumberControl : TextBox
    {
        private const string _POINT = ".";
        private const string _SUBTRACT = "-";
        private const char _ZEROR = '0';
        private const int _LIMIT = 0;

        /*
        #region 属性值验证
        /// <summary>
        /// 
        /// </summary>
        public double Value2
        {
            get
            {
                return (double)base.GetValue(ValueProperty2);
            }
            set
            {
                base.SetValue(ValueProperty2, value);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty ValueProperty2 =
            DependencyProperty.Register(nameof(Value2), typeof(double), typeof(NumberControl),
                new FrameworkPropertyMetadata(0d,
                    FrameworkPropertyMetadataOptions.None,
                    new PropertyChangedCallback(ValuePropertyChangedCallback),
                    new CoerceValueCallback(ValueCoerceValueCallback)),
                    new ValidateValueCallback(ValueValidateValueCallback));

        private static void ValuePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //ValueCoerceValueCallback与ValueValidateValueCallback都通过,才会触发
            throw new NotImplementedException();
        }

        private static bool ValueValidateValueCallback(object value)
        {
            //对值进行验证,通过返回true,不通过返回flase
            throw new NotImplementedException();
        }

        private static object ValueCoerceValueCallback(DependencyObject d, object baseValue)
        {
            //对值进行限定,强制修改值为多少
            throw new NotImplementedException();
        }
        #endregion

        #region 依赖属性值改变监听
        /// <summary>
        /// 依赖属性值改变监听
        /// </summary>
        private void DependencyPropertyListen()
        {
            var descriptor = System.ComponentModel.DependencyPropertyDescriptor.FromProperty(NumberControl.ValueProperty2, typeof(NumberControl));
            descriptor.AddValueChanged(this, this.Value22Changed);
        }

        private void Value22Changed(object sender, EventArgs e)
        {

        }
        #endregion

       

        #region 附加属性
        /// <summary>
        /// 
        /// </summary>
        public double Angle
        {
            get
            {
                return (double)base.GetValue(AngleProperty);
            }
            set
            {
                base.SetValue(AngleProperty, value);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static readonly DependencyProperty AngleProperty = DependencyProperty.RegisterAttached(nameof(Angle), typeof(double), typeof(NumberControl),
                new FrameworkPropertyMetadata(0d,
                    FrameworkPropertyMetadataOptions.None,
                    new PropertyChangedCallback(AValuePropertyChangedCallback),
                    new CoerceValueCallback(AValueCoerceValueCallback)),
                    new ValidateValueCallback(AValueValidateValueCallback));

        private static bool AValueValidateValueCallback(object value)
        {
            throw new NotImplementedException();
        }

        private static object AValueCoerceValueCallback(DependencyObject d, object baseValue)
        {
            throw new NotImplementedException();
        }

        private static void AValuePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ele = d as UIElement;
            if (ele == null)
            {
                return;
            }

            ele.RenderTransformOrigin = new Point(0.5, 0.5);
            ele.RenderTransform = new System.Windows.Media.RotateTransform((double)e.NewValue);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <param name="angle"></param>
        public static void SetAngle(DependencyObject dependencyObject, double angle)
        {
            dependencyObject.SetValue(AngleProperty, angle);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        public static double GetAngle(DependencyObject dependencyObject)
        {
            return (double)dependencyObject.GetValue(AngleProperty);
        }
        #endregion
         */


        #region 依赖属性
        /// <summary>
        /// 辅助文本依赖属性
        /// </summary>
        public static readonly DependencyProperty AssistTextProperty =
            DependencyProperty.Register(nameof(AssistText), typeof(string), typeof(NumberControl),
                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 值依赖属性
        /// </summary>
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register(nameof(Value), typeof(double), typeof(NumberControl),
                new FrameworkPropertyMetadata(0d, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 值是否允许为NaN依赖属性
        /// </summary>
        public static readonly DependencyProperty AllowNaNProperty =
            DependencyProperty.Register(nameof(AllowNaN), typeof(bool), typeof(NumberControl),
                new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnPropertyChangedCallback)));


        /// <summary>
        /// 最小值依赖属性
        /// </summary>
        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register(nameof(Minimum), typeof(double), typeof(NumberControl),
                new FrameworkPropertyMetadata(double.MinValue, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 最大值依赖属性
        /// </summary>
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register(nameof(Maximum), typeof(double), typeof(NumberControl),
                new FrameworkPropertyMetadata(double.MaxValue, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 获取或设置整小数显示位数依赖属性
        /// </summary>
        public static readonly DependencyProperty DecimalWidthProperty =
            DependencyProperty.Register(nameof(DecimalWidth), typeof(int), typeof(NumberControl),
                new FrameworkPropertyMetadata(-1, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 整数显示位数依赖属性
        /// </summary>
        public static readonly DependencyProperty IntegerWidthProperty =
            DependencyProperty.Register(nameof(IntegerWidth), typeof(int), typeof(NumberControl),
                new FrameworkPropertyMetadata(-1, new PropertyChangedCallback(OnPropertyChangedCallback)));

        ///// <summary>
        ///// 单击向上或向下按钮时，数字显示框（也称作 up-down 控件）递增或递减的值依赖属性
        ///// </summary>
        //public static readonly DependencyProperty IncrementProperty =
        //    DependencyProperty.Register(nameof(Increment), typeof(double), typeof(NumberControl),
        //        new FrameworkPropertyMetadata(double.NaN, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 转换器依赖属性
        /// </summary>
        public static readonly DependencyProperty ConverterProperty =
            DependencyProperty.Register(nameof(Converter), typeof(IValueConverter), typeof(NumberControl),
                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChangedCallback)));





        /// <summary>
        /// 增加步进值命令依赖属性
        /// </summary>
        public static readonly DependencyProperty IncrementCommandProperty =
            DependencyProperty.Register(nameof(IncrementCommand), typeof(ICommand), typeof(NumberControl),
                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 减小步进值命令依赖属性
        /// </summary>
        public static readonly DependencyProperty DecrementCommandProperty =
            DependencyProperty.Register(nameof(DecrementCommand), typeof(ICommand), typeof(NumberControl),
                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 增加或减小步进值依赖属性
        /// </summary>
        public static readonly DependencyProperty StepProperty =
            DependencyProperty.Register(nameof(Step), typeof(double), typeof(NumberControl),
                new FrameworkPropertyMetadata(1.0d, new PropertyChangedCallback(OnPropertyChangedCallback)));

        /// <summary>
        /// 获取或设置增加步进值命令
        /// </summary>
        public ICommand IncrementCommand
        {
            get
            {
                return (ICommand)base.GetValue(IncrementCommandProperty);
            }
            set
            {
                base.SetValue(IncrementCommandProperty, value);
            }
        }

        /// <summary>
        /// 获取或设置减小步进值命令
        /// </summary>
        public ICommand DecrementCommand
        {
            get
            {
                return (ICommand)base.GetValue(DecrementCommandProperty);
            }
            set
            {
                base.SetValue(DecrementCommandProperty, value);
            }
        }

        /// <summary>
        /// 获取或设置增加或减小步进值
        /// </summary>
        public double Step
        {
            get
            {
                return (double)base.GetValue(StepProperty);
            }
            set
            {
                base.SetValue(StepProperty, value);
            }
        }

        /// <summary>
        /// 获取或设置辅助文本
        /// </summary>
        public string AssistText
        {
            get
            {
                return (string)base.GetValue(AssistTextProperty);
            }
            set
            {
                base.SetValue(AssistTextProperty, value);
            }
        }


        /// <summary>
        /// 值改变事件
        /// </summary>
        public event EventHandler<NumberValueChangedArgs> ValueChanged;

        /// <summary>
        /// 获取或设置值
        /// </summary>
        public double Value
        {
            get
            {
                return (double)base.GetValue(ValueProperty);
            }
            set
            {
                if (!double.IsNaN(value))
                {
                    if (value - this.Minimum < this._precision || value - this.Maximum > this._precision)
                    {
                        throw new ArgumentOutOfRangeException($"值超出最大最小值范围{this.Minimum}-{this.Maximum}");
                    }

                    string valueStr = value.ToString();
                    int pointIndex = valueStr.IndexOf(_POINT);
                    int decimalWidth = this.DecimalWidth;
                    if (decimalWidth >= _LIMIT &&
                        pointIndex > 0 &&
                        valueStr.Length - (pointIndex + 1) > decimalWidth)
                    {
                        valueStr = valueStr.Substring(0, pointIndex + 1 + decimalWidth);
                        value = double.Parse(valueStr);
                    }
                }

                var oldValue = this.Value;
                base.SetValue(ValueProperty, value);

                var handler = this.ValueChanged;
                if (handler != null)
                {
                    handler(this, new NumberValueChangedArgs(oldValue, value));
                }
            }
        }

        /// <summary>
        /// 获取或设置值是否允许为NaN,true:允许;false:不允许
        /// </summary>
        public bool AllowNaN
        {
            get
            {
                return (bool)base.GetValue(AllowNaNProperty);
            }
            set
            {
                base.SetValue(AllowNaNProperty, value);
            }
        }

        /// <summary>
        /// 获取或设置数字显示框的最小允许值,为double.NaN时无限制
        /// </summary>
        public double Minimum
        {
            get
            {
                return (double)base.GetValue(MinimumProperty);
            }
            set
            {
                base.SetValue(MinimumProperty, value);
            }
        }

        /// <summary>
        /// 获取或设置数字显示框的最大允许值,为double.NaN时无限制
        /// </summary>
        public double Maximum
        {
            get
            {
                return (double)base.GetValue(MaximumProperty);
            }
            set
            {
                base.SetValue(MaximumProperty, value);
            }
        }

        private double _precision = 0d;
        /// <summary>
        /// 获取或设置数据比较精度
        /// </summary>
        public double Precision
        {
            get { return _precision; }
            set { _precision = value; }
        }

        /// <summary>
        /// 获取或设置整小数显示位数,小于0表示无限制
        /// </summary>
        public int DecimalWidth
        {
            get
            {
                return (int)base.GetValue(DecimalWidthProperty);
            }
            set
            {
                base.SetValue(DecimalWidthProperty, value);
            }
        }


        /// <summary>
        /// 获取或设置整数显示位数,小于0表示无限制
        /// </summary>
        public int IntegerWidth
        {
            get
            {
                return (int)base.GetValue(IntegerWidthProperty);
            }
            set
            {
                base.SetValue(IntegerWidthProperty, value);
            }
        }

        /// <summary>
        /// 转换器
        /// </summary>
        public IValueConverter Converter
        {
            get
            {
                return (IValueConverter)base.GetValue(ConverterProperty);
            }
            set
            {
                base.SetValue(ConverterProperty, value);
            }
        }

        ///// <summary>
        ///// 获取或设置单击向上或向下按钮时，数字显示框（也称作 up-down 控件）递增或递减的值
        ///// </summary>
        //public double Increment
        //{
        //    get
        //    {
        //        return (double)base.GetValue(IncrementProperty);
        //    }
        //    set
        //    {
        //        base.SetValue(IncrementProperty, value);
        //    }
        //}



        private static void OnPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var selfControl = (NumberControl)d;

            if (e.Property == MinimumProperty)
            {
                selfControl.UpdateValueByMinimum((double)e.NewValue);
            }
            else if (e.Property == MaximumProperty)
            {
                selfControl.UpdateValueByMaximum((double)e.NewValue);
            }
            else if (e.Property == AllowNaNProperty)
            {
                selfControl.UpdateValueByAllowNaN((bool)e.NewValue);
            }
            //else if (e.Property == DecimalPlacesProperty)
            //{
            //    selfControl.UpdatePrecision((int)e.NewValue);
            //}


            if (e.Property == ValueProperty ||
                 e.Property == DecimalWidthProperty ||
                 e.Property == IntegerWidthProperty ||
                 e.Property == ConverterProperty)
            {
                selfControl.UpdateTextByValue(selfControl.Value);
            }
        }

        private void UpdateTextByValue(double value)
        {
            this._setShowText = true;
            try
            {
                if (double.IsNaN(value))
                {
                    this.Text = string.Empty;
                    return;
                }

                if (this.Converter == null)
                {
                    this.Text = value.ToString();
                    this.FormatShowText();
                }
                else
                {
                    object result = this.Converter.Convert(value, null, null, null);
                    if (result != null)
                    {
                        this.Text = result.ToString();
                    }
                    else
                    {
                        this.Text = string.Empty;
                    }
                }
                this.SelectionStart = this.Text.Length;
            }
            finally
            {
                this._setShowText = false;
            }
        }

        private bool _setShowText = false;
        private void FormatShowText()
        {
            int decimalWidth = this.DecimalWidth;
            int integerWidth = this.IntegerWidth;

            if (decimalWidth < _LIMIT && integerWidth < _LIMIT)
            {
                return;
            }

            int pointIndex = this.Text.IndexOf('.');
            bool minusNumber = this.Text.StartsWith("-");
            int count;
            string fillStr;
            int insertFillStrIndex;

            if (decimalWidth > 0)
            {
                if (integerWidth > _LIMIT)
                {
                    //整数+小数

                    //整数
                    if (pointIndex >= 0)
                    {
                        count = integerWidth - pointIndex;
                    }
                    else
                    {
                        count = integerWidth - this.Text.Length;
                    }

                    insertFillStrIndex = 0;
                    if (minusNumber)
                    {
                        count += 1;
                        insertFillStrIndex = 1;
                    }

                    if (count > 0)
                    {
                        fillStr = new string('0', count);
                        this.Text = this.Text.Insert(insertFillStrIndex, fillStr);
                    }

                    //小数
                    pointIndex = this.Text.IndexOf('.');
                    if (pointIndex >= 0)
                    {
                        insertFillStrIndex = pointIndex + 1;
                        count = decimalWidth - (this.Text.Length - insertFillStrIndex);
                        if (count > 0)
                        {
                            fillStr = new string('0', count);
                            this.Text += fillStr;
                        }
                    }
                    else
                    {
                        fillStr = new string('0', decimalWidth);
                        this.Text = $"{this.Text}.{fillStr}";
                    }
                }
                else
                {
                    //只有小数
                    if (pointIndex < 0)
                    {
                        fillStr = new string('0', decimalWidth);
                        this.Text = $"{this.Text}.{fillStr}";
                    }
                    else
                    {
                        insertFillStrIndex = pointIndex + 1;
                        count = decimalWidth - (this.Text.Length - insertFillStrIndex);
                        if (count > 0)
                        {
                            fillStr = new string('0', count);
                            this.Text += fillStr;
                        }
                    }
                }
            }
            else
            {
                if (integerWidth > 0)
                {
                    //只有整数
                    if (pointIndex >= 0)
                    {
                        count = integerWidth - pointIndex;
                    }
                    else
                    {
                        count = integerWidth - this.Text.Length;
                    }

                    insertFillStrIndex = 0;
                    if (minusNumber)
                    {
                        count -= 1;
                        insertFillStrIndex = 1;
                    }

                    if (count > 0)
                    {
                        fillStr = new string('0', count);
                        this.Text = this.Text.Insert(insertFillStrIndex, fillStr);
                    }
                }
                else
                {
                    //无限制
                }
            }
        }


        /*
        private void UpdatePrecision(int decimalPlaces)
        {
            if (decimalPlaces > 0)
            {
                this._precision = 1d / Math.Pow(10d, (double)(decimalPlaces + 1));
            }
            else
            {
                this._precision = 0d;
            }
        }
        */

        private void UpdateValueByAllowNaN(bool allowNaN)
        {
            if (allowNaN)
            {
                return;
            }

            if (double.IsNaN(this.Value))
            {
                this.Value = this.Minimum;
            }
        }

        private void UpdateValueByMaximum(double value)
        {
            if (!double.IsNaN(value) && this.Value - value > this._precision)
            {
                this.Value = value;
            }
        }

        private void UpdateValueByMinimum(double value)
        {
            if (!double.IsNaN(value) && this.Value - value < this._precision)
            {
                this.Value = value;
            }
        }
        #endregion






        private bool _enablePreviewMouseDown = true;
        private bool _valueNoComit = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        public NumberControl()
        {
            this.HorizontalContentAlignment = HorizontalAlignment.Left;
            this.VerticalContentAlignment = VerticalAlignment.Center;
            //this.IsInactiveSelectionHighlightEnabled = false;//默认为false,如果设置为true,则控件失去焦点后文本是灰色的.不晓得到底有何用处.也不知道当时为毛要加这个属性
            this.UndoLimit = 2;
            this.UpdateTextByValue(this.Value);

            InputMethod.SetPreferredImeState(this, InputMethodState.Off);//禁止输入中文

            var pasteCommand = new CommandBinding(ApplicationCommands.Paste);
            pasteCommand.Executed += PasteCommand_Executed;
            this.CommandBindings.Add(pasteCommand);

            //var copyCommand = new CommandBinding(ApplicationCommands.Copy);
            //copyCommand.Executed += CopyCommand_Executed; ;
            //this.CommandBindings.Add(copyCommand);

            this.DecrementCommand = new NumberUpDownControlEditCommand(this.DecrementCommandCallback);
            this.IncrementCommand = new NumberUpDownControlEditCommand(this.IncrementCommandCallback);
        }

        private void IncrementCommandCallback(object parameter)
        {
            var newValue = this.Value + this.Step;
            if (this.Maximum - newValue >= this._precision)
            {
                this.Value = newValue;
            }
        }


        private void DecrementCommandCallback(object parameter)
        {
            var newValue = this.Value - this.Step;
            if (this.Minimum - newValue <= this._precision)
            {
                this.Value = newValue;
            }
        }

        private void CopyCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            object data;
            if (this.SelectionLength == 0)
            {
                data = this.Text;
            }
            else
            {
                data = this.SelectedText;
            }

            Clipboard.SetData(System.Windows.DataFormats.Text, data);
            if (e != null)
            {
                e.Handled = true;
            }
        }

        private void PasteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (e != null)
            {
                e.Handled = true;
            }

            string text = Clipboard.GetText(TextDataFormat.Text);
            if (string.IsNullOrWhiteSpace(text))
            {
                return;
            }

            double value;
            if (!double.TryParse(text, out value))
            {
                return;
            }

            if (value - this.Minimum < this._precision || value - this.Maximum > this._precision)
            {
                return;
            }

            this.Value = value;
        }
    }


    /// <summary>
    /// number控件值改变事件参数
    /// </summary>
    public class NumberValueChangedArgs : EventArgs
    {
        /// <summary>
        /// 旧值
        /// </summary>
        public double OldValue { get; private set; }

        /// <summary>
        /// 新值
        /// </summary>
        public double NewValue { get; private set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="oldValue">旧值</param>
        /// <param name="newValue">新值</param>
        public NumberValueChangedArgs(double oldValue, double newValue)
        {
            this.OldValue = oldValue;
            this.NewValue = newValue;
        }
    }

    internal class NumberUpDownControlEditCommand : ICommand
    {
        private readonly Action<object> _editAction;
        public NumberUpDownControlEditCommand(Action<object> editAction)
        {
            this._editAction = editAction;
        }

        /// <summary>
        /// 
        /// </summary>
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            var handler = this.CanExecuteChanged;
            if (handler != null)
            {
                var args = new CanExecuteArgs();
                handler(this, args);
                return args.CanExecute;
            }
            else
            {
                return true;
            }
        }

        public void Execute(object parameter)
        {
            this._editAction(parameter);
        }
    }
}
